"""
使用真实数据获取函数进行空调负荷预测训练和测试
集成您现有的calculate_load函数，实现完整的训练预测流程
"""

import sys
import os
import pandas as pd
import numpy as np
import datetime
from typing import Dict, Tuple
import warnings
warnings.filterwarnings('ignore')

# 添加项目路径
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(project_root)

try:
    # 导入真实的数据获取函数
    print(f"📁 项目根目录: {project_root}")
    print(f"📂 当前Python路径: {sys.path[-1]}")
    from App.System_of_C.read_and_process_data.read_data_for_Loadpredict import calculate_load
    REAL_DATA_AVAILABLE = True
    print("✅ 成功导入真实数据获取函数")
except ImportError as e:
    print(f"⚠️ 无法导入真实数据获取函数: {e}")
    print("💡 将使用模拟数据进行演示")
    REAL_DATA_AVAILABLE = False

try:
    # 导入工作流系统 - 🔧 添加配置类和工作流类
    from load_prediction_workflow import create_workflow, quick_train_and_predict, HVACLoadPredictionWorkflow
    from enhanced_hvac_transformer import EnhancedHVACConfig
    WORKFLOW_AVAILABLE = True
    print("✅ 成功导入工作流系统和防过拟合配置")
except ImportError as e:
    print(f"❌ 无法导入工作流系统: {e}")
    WORKFLOW_AVAILABLE = False

try:
    # 检查深度学习依赖
    import torch
    TORCH_AVAILABLE = True
    print("✅ torch可用，可以进行深度学习训练")
except ImportError:
    TORCH_AVAILABLE = False
    print("⚠️ torch不可用，只能进行数据处理测试")


class RealDataTrainingDemo:
    """真实数据训练演示类"""
    
    def __init__(self):
        self.workflow = None
        self.training_result = None
        
    def create_anti_overfitting_config(self):
        """创建防过拟合配置"""
        print("🛡️ 创建防过拟合配置...")
        
        anti_overfitting_config = EnhancedHVACConfig(
            # 🔧 减小模型复杂度
            d_model=64,                 # 从256降到64
            n_heads=4,                  # 从8降到4  
            n_layers=2,                 # 从6降到2
            d_ff=256,                   # 从1024降到256
            
            # 🔧 强化正则化
            dropout=0.4,                # 从0.1增加到0.4
            
            # 时间参数保持不变
            seq_len=168,                # 一周历史数据
            pred_len=24,                # 预测24小时
            
            # 特征参数
            n_env_features=2,           # 温度和含湿量
            n_cyclical_features=6,      
            n_statistical_features=8,
            
            # 设备配置
            device="cuda" if torch.cuda.is_available() else "cpu"
        )
        
        print("📊 防过拟合配置详情:")
        print(f"   🏗️ 模型维度: {anti_overfitting_config.d_model} (减小75%)")
        print(f"   🎯 注意力头: {anti_overfitting_config.n_heads} (减少50%)")
        print(f"   📚 层数: {anti_overfitting_config.n_layers} (减少67%)")
        print(f"   🛡️ Dropout率: {anti_overfitting_config.dropout} (增加300%)")
        
        return anti_overfitting_config
        
    def provide_error_solutions(self, error_type: str, error_details: str):
        """提供详细的错误解决方案"""
        print(f"\n❌ 真实数据获取失败")
        print(f"🔍 错误类型: {error_type}")
        print(f"📝 错误详情: {error_details}")
        
        print(f"\n💡 可能的解决方案:")
        
        if "404" in error_details or "API" in error_details:
            print("   📡 API连接问题:")
            print("   1. 检查API服务是否启动")
            print("   2. 验证API端点URL是否正确")
            print("   3. 确认网络连接正常")
            print("   4. 检查防火墙设置")
            
        if "认证" in error_details or "token" in error_details.lower():
            print("   🔐 认证问题:")
            print("   1. 检查API密钥或token是否有效")
            print("   2. 验证用户权限")
            print("   3. 更新过期的认证信息")
            
        if "数据库" in error_details or "connection" in error_details.lower():
            print("   🗄️ 数据库连接问题:")
            print("   1. 检查数据库服务状态")
            print("   2. 验证连接字符串")
            print("   3. 确认数据库权限")
            print("   4. 检查网络连接")
            
        if "JSON" in error_details or "解析" in error_details:
            print("   📄 数据格式问题:")
            print("   1. 检查API返回的数据格式")
            print("   2. 验证响应是否为有效JSON")
            print("   3. 检查服务器错误页面")
            
        print(f"\n🔧 立即检查步骤:")
        print("   1. 手动访问API端点确认服务状态")
        print("   2. 检查系统日志获取详细错误信息")
        print("   3. 验证配置文件中的连接参数")
        print("   4. 联系系统管理员确认服务状态")
        
        print(f"\n📞 技术支持:")
        print("   - 收集完整的错误日志")
        print("   - 记录系统环境信息")
        print("   - 提供最近的系统变更记录")
    
    def test_data_function(self, data_function, test_period_days: int = 1):
        """测试数据获取函数"""
        print(f"\n🧪 测试数据获取函数...")
        
        try:
            # 设置测试时间范围
            #end_time = datetime.datetime.now()
            end_time = datetime.datetime(2025, 9, 10, 0, 0, 0)
            start_time = end_time - datetime.timedelta(days=test_period_days)
            
            start_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
            end_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
            
            print(f"📅 测试时间范围: {start_str} 至 {end_str}")
            
            # 调用数据获取函数
            data = data_function(start_str, end_str)
            
            if data is None or len(data) == 0:
                print("⚠️ 数据获取函数返回空数据")
                print("💡 可能原因: API不可用、数据库连接问题、时间范围无数据")
                return False
            
            print(f"✅ 数据获取成功: {data.shape}")
            
            # 检查数据格式
            required_cols = ['timestamp', 'swt', 'swh', 'real_load']
            missing_cols = [col for col in required_cols if col not in required_cols]
            
            if missing_cols:
                print(f"❌ 数据格式错误，缺少列: {missing_cols}")
                print(f"实际列名: {list(data.columns)}")
                return False
            
            print("✅ 数据格式验证通过")
            
            # 数据质量检查
            print(f"📊 数据质量:")
            print(f"   时间范围: {data['timestamp'].min()} 至 {data['timestamp'].max()}")
            print(f"   负荷范围: {data['real_load'].min():.2f} - {data['real_load'].max():.2f}")
            print(f"   温度范围: {data['swt'].min():.2f} - {data['swt'].max():.2f}°C")
            print(f"   含湿量范围: {data['swh'].min():.4f} - {data['swh'].max():.4f}")
            
            # 检查缺失值
            missing_counts = data.isnull().sum()
            total_missing = missing_counts.sum()
            
            if total_missing > 0:
                print(f"⚠️ 发现缺失数据:")
                for col, count in missing_counts.items():
                    if count > 0:
                        print(f"   {col}: {count} 个缺失值")
            else:
                print("✅ 无缺失数据")
            
            # 检查非零负荷数据
            non_zero_load = data[data['real_load'] != 0]
            zero_ratio = (len(data) - len(non_zero_load)) / len(data) * 100
            
            print(f"📈 负荷数据统计:")
            print(f"   非零负荷记录: {len(non_zero_load)}/{len(data)}")
            print(f"   零值比例: {zero_ratio:.1f}%")
            
            if len(non_zero_load) < 0.5 * len(data):
                print("⚠️ 零负荷数据过多，可能影响训练效果")
            
            return True
            
        except Exception as e:
            error_str = str(e)
            self.provide_error_solutions("数据获取异常", error_str)
            print(f"\n❌ 真实数据获取测试失败，系统无法继续")
            print("🚫 系统设计为仅使用真实数据，不提供模拟数据回退")
            print("🔧 请解决上述问题后重新运行")
            raise RuntimeError(f"真实数据获取失败: {error_str}") from e
    
    def test_workflow_integration(self, data_function):
        """测试工作流集成"""
        print(f"\n🔧 测试工作流集成...")
        
        if not WORKFLOW_AVAILABLE:
            print("❌ 工作流系统不可用")
            return False
        
        try:
            # 创建工作流
            self.workflow = create_workflow(data_function)
            print("✅ 工作流创建成功")
            
            # 测试数据处理
            # end_time = datetime.datetime.now()
            end_time = datetime.datetime(2025, 9, 10, 0, 0, 0)
            start_time = end_time - datetime.timedelta(days=10)  # 10天数据确保足够训练
            
            start_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
            end_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
            
            print(f"🔄 测试数据处理: {start_str} 至 {end_str}")
            
            processed_data, raw_data = self.workflow.fetch_and_process_data(start_str, end_str)
            
            print(f"✅ 数据处理成功")
            print(f"   原始数据: {len(raw_data)} 条记录")
            print(f"   处理后特征数: {len(processed_data)}")
            
            # 检查是否有足够数据进行训练
            required_samples = self.workflow.model_config.seq_len + self.workflow.model_config.pred_len
            
            if len(raw_data) >= required_samples:
                print(f"✅ 数据量充足，可进行训练 ({len(raw_data)} >= {required_samples})")
                return True
            else:
                print(f"⚠️ 数据量不足，需要更长时间范围 ({len(raw_data)} < {required_samples})")
                return False
        
        except Exception as e:
            print(f"❌ 工作流集成测试失败: {e}")
            return False
    
    def run_training(self, data_function, training_days: int = 60):  # 🔧 增加训练天数
        """运行防过拟合模型训练"""
        print(f"\n🚀 开始防过拟合模型训练...")
        print(f"🛡️ 采用方案1(直接工作流) + 方案3(防过拟合配置)")
        
        if not TORCH_AVAILABLE:
            print("❌ PyTorch不可用，无法进行深度学习训练")
            print("💡 请安装: pip install torch")
            return False
        
        if not WORKFLOW_AVAILABLE:
            print("❌ 工作流系统不可用")
            return False
        
        try:
            # 🔧 方案3: 创建防过拟合配置
            anti_overfitting_config = self.create_anti_overfitting_config()
            
            # 设置训练时间范围
            # end_time = datetime.datetime.now()
            end_time = datetime.datetime(2025, 9, 10, 0, 0, 0)
            start_time = end_time - datetime.timedelta(days=training_days)
            
            start_str = start_time.strftime('%Y-%m-%d %H:%M:%S')
            end_str = end_time.strftime('%Y-%m-%d %H:%M:%S')
            
            print(f"📅 训练时间范围: {start_str} 至 {end_str} ({training_days}天)")
            print("=" * 80)
            
            # 🔧 方案1: 直接使用工作流接口，精确控制超参数
            workflow = HVACLoadPredictionWorkflow(
                data_fetch_function=data_function,
                model_config=anti_overfitting_config  # 使用防过拟合配置
            )
            
            print("🎯 防过拟合训练参数:")
            print(f"   📚 训练轮数: 100 (让模型慢慢学习)")
            print(f"   📦 批次大小: 128 (增大batch size)")
            print(f"   📉 学习率: 0.00005 (非常保守)")
            print(f"   🛑 早停耐心: 15 (更早停止)")
            print("=" * 80)
            
            # 🔍 训练前数据分布诊断
            print("🔍 开始训练前数据分布诊断...")
            try:
                # 获取训练数据进行分析
                X, y = workflow.prepare_training_data(start_str, end_str)
                
                print(f"📊 完整数据集统计:")
                print(f"   样本数量: {len(y)}")
                print(f"   目标值范围: [{y.min():.6f}, {y.max():.6f}]")
                print(f"   目标值均值: {y.mean():.6f}")
                print(f"   目标值标准差: {y.std():.6f}")
                
                # 检查数据分割后的分布
                train_size = int(len(y) * 0.8)
                y_train = y[:train_size]
                y_val = y[train_size:]
                
                print(f"📊 训练/验证集分布:")
                print(f"   训练集: {len(y_train)}个样本")
                print(f"      范围: [{y_train.min():.6f}, {y_train.max():.6f}]")
                print(f"      均值±std: {y_train.mean():.6f}±{y_train.std():.6f}")
                print(f"   验证集: {len(y_val)}个样本")
                print(f"      范围: [{y_val.min():.6f}, {y_val.max():.6f}]")
                print(f"      均值±std: {y_val.mean():.6f}±{y_val.std():.6f}")
                
                # 检查分布差异
                mean_diff = abs(y_train.mean() - y_val.mean())
                combined_std = (y_train.std() + y_val.std()) / 2
                
                if mean_diff > combined_std:
                    print("🚨 警告: 训练集和验证集分布差异较大!")
                    print(f"   均值差异: {mean_diff:.6f}")
                    print(f"   建议: 检查数据排序或使用随机划分")
                else:
                    print("✅ 训练集和验证集分布正常")
                
                # 检查数据中是否有异常值
                if y.std() == 0:
                    print("🚨 严重问题: 目标值标准差为0，所有值相同!")
                elif y.std() < 0.001:
                    print("⚠️ 警告: 目标值变化极小，可能影响学习")
                
            except Exception as e:
                print(f"❌ 数据诊断失败: {e}")
            
            print("=" * 80)
            
            # 精确控制的训练
            training_result = workflow.train_model(
                start_time=start_str,
                end_time=end_str,
                epochs=100,                 # 🔧 增加epoch让模型慢慢学习
                batch_size=32,             # 🔧 增大batch size提高稳定性
                learning_rate=0.001,      # 🔧 非常小的学习率防止过拟合
                save_dir="anti_overfitting_models"
            )
            
            # 包装结果以保持兼容性
            self.training_result = {
                'training_result': training_result,
                'workflow': workflow,
                'config_used': anti_overfitting_config
            }
            
            print(f"\n🎉 防过拟合训练完成!")
            print("=" * 60)
            
            # 显示训练结果
            print(f"📊 训练结果:")
            print(f"   🏆 最佳验证损失: {training_result['best_val_loss']:.6f}")
            print(f"   📊 最终验证MAE: {training_result['final_val_mae']:.6f}")
            print(f"   🕐 总训练轮数: {training_result['total_epochs']}")
            
            # 🔍 过拟合检测
            final_train_loss = training_result.get('final_train_loss', 0)
            final_val_loss = training_result['final_val_loss']
            overfitting_ratio = final_val_loss / max(final_train_loss, 1e-8)
            
            print(f"\n🔍 过拟合分析:")
            print(f"   🔸 训练损失: {final_train_loss:.6f}")
            print(f"   🔹 验证损失: {final_val_loss:.6f}")
            print(f"   📈 过拟合比例: {overfitting_ratio:.2f}")
            
            if overfitting_ratio < 1.5:
                print("   ✅ 健康学习状态！")
            elif overfitting_ratio < 3.0:
                print("   ⚠️ 轻微过拟合，可接受")
            else:
                print("   🚨 仍有过拟合，建议进一步调整")
            
            print("=" * 60)
            print(f"💾 模型已保存到: anti_overfitting_models/")
            
            return True
            
        except Exception as e:
            print(f"❌ 防过拟合训练失败: {e}")
            print("\n💡 故障排除建议:")
            print("   1. 检查数据时间范围和质量")
            print("   2. 确认GPU内存是否充足")
            print("   3. 尝试进一步减小模型规模")
            print("   4. 检查数据获取函数是否正常")
            import traceback
            print(f"\n📋 详细错误信息:\n{traceback.format_exc()}")
            return False
    
    def run_prediction_test(self):
        """运行预测测试"""
        print(f"\n🔮 测试实时预测功能...")
        
        if self.training_result is None:
            print("❌ 需要先完成模型训练")
            return False
        
        try:
            workflow = self.training_result['workflow']
            
            # 设置预测时间范围
            # current_time = datetime.datetime.now()
            current_time = datetime.datetime(2025, 9, 10, 0, 0, 0)
            hist_start = current_time - datetime.timedelta(hours=168)  # 一周历史
            
            hist_start_str = hist_start.strftime('%Y-%m-%d %H:%M:%S')
            current_str = current_time.strftime('%Y-%m-%d %H:%M:%S')
            
            print(f"📅 历史数据: {hist_start_str} 至 {current_str}")
            
            # 进行实时预测
            predictions, stats = workflow.predict_with_realtime_data(
                historical_start=hist_start_str,
                historical_end=current_str,
                pred_hours=24
            )
            
            print(f"✅ 预测成功!")
            print(f"📊 预测统计:")
            print(f"   预测点数: {len(predictions)}")
            print(f"   平均负荷: {stats['mean_load']:.2f} kW")
            print(f"   峰值负荷: {stats['max_load']:.2f} kW")
            print(f"   最低负荷: {stats['min_load']:.2f} kW")
            print(f"   总耗电量: {stats['total_consumption']:.2f} kWh")
            
            if stats['peak_hour']:
                print(f"   峰值时间: {stats['peak_hour'].strftime('%H:%M')}")
            
            return True
            
        except Exception as e:
            print(f"❌ 预测测试失败: {e}")
            return False


def main():
    """主函数"""
    print("🏢 真实数据空调负荷预测训练演示")
    print("集成您现有的数据获取函数进行完整训练")
    print("=" * 60)
    
    demo = RealDataTrainingDemo()
    
    # 检查真实数据获取函数可用性
    if not REAL_DATA_AVAILABLE:
        print("❌ 真实数据获取函数不可用")
        print("🔍 导入失败原因: 无法导入calculate_load函数")
        print("\n💡 解决方案:")
        print("   1. 检查App/System_of_C/read_and_process_data/路径是否存在")
        print("   2. 确认read_data_for_Loadpredict.py文件完整")
        print("   3. 验证相关依赖库已安装")
        print("   4. 检查Python路径配置")
        print("\n❌ 系统终止运行")
        return
    
    print("✅ 真实数据获取函数导入成功: calculate_load")
    print("🎯 系统设计为仅使用真实数据，确保数据准确性")
    
    # 第1步: 测试真实数据获取函数
    print("\n" + "="*60)
    print("📋 第1步: 测试真实数据获取功能")
    print("="*60)
    
    try:
        demo.test_data_function(calculate_load)
        print("✅ 真实数据获取成功，继续训练流程")
        data_function = calculate_load
    except RuntimeError as e:
        print(f"\n❌ 系统运行终止")
        print("🚫 无法获取真实数据，程序退出")
        return
    
    # 第2步: 测试工作流集成
    print("\n" + "="*60)
    print("🔧 第2步: 测试工作流集成")
    print("="*60)
    
    if not demo.test_workflow_integration(data_function):
        print("❌ 工作流集成测试失败，终止演示")
        return
    
    # 第3步: 询问是否进行训练
    print("\n" + "="*60)
    print("🚀 第3步: 模型训练")
    print("="*60)
    
    if TORCH_AVAILABLE:
        print("🛡️ 准备启动防过拟合训练...")
        print("📊 新配置：60天数据 + 小模型 + 高dropout + 低学习率")
        user_input = input("是否开始防过拟合模型训练？(这可能需要更长时间) [y/N]: ")
        if user_input.lower() in ['y', 'yes']:
            if demo.run_training(data_function, training_days=60):  # 🔧 明确使用60天训练数据
                # 第4步: 预测测试
                print("\n" + "="*60)
                print("🔮 第4步: 预测测试")
                print("="*60)
                demo.run_prediction_test()
        else:
            print("跳过模型训练")
    else:
        print("❌ PyTorch不可用，跳过训练步骤")
        print("💡 安装命令: pip install torch")
    
    # 总结
    print("\n" + "="*60)
    print("✅ 演示完成!")
    print("="*60)
    
    print("\n📋 演示总结:")
    print("   ✓ 数据获取功能测试")
    print("   ✓ 工作流集成测试")
    
    if TORCH_AVAILABLE and demo.training_result:
        print("   ✓ 模型训练完成")
        print("   ✓ 实时预测测试")
        
        package_dir = demo.training_result['training_result'].get('package_dir')
        if package_dir:
            print(f"\n🎯 模型已保存到: {package_dir}")
            print("您可以使用以下代码加载和使用模型:")
            print(f"""
from load_prediction_workflow import load_enhanced_deployment_model

# 加载模型
predictor, processor = load_enhanced_deployment_model("{package_dir}")

# 进行预测
predictions, stats = predictor.predict_remaining_day()
""")
    
    print("\n🎉 您的空调负荷预测系统已就绪!")


if __name__ == "__main__":
    main()
